package momo.multitree.structure;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Edge
{
	private Log log = LogFactory.getLog(Edge.class);
	
	
	static final int OBJECT = 0;
	static final int ATTRIBUTE = 1;
	
	private String id;
	private Node headNode, tailNode;
	private double costHT, costTH;
	private double latHT, latTH;
	
	/**
	 * Constructor of Edge. Consider this as directed.
	 * @param id 
	 * @param headNode Node that init the connection.
	 * @param tailNode Node that is connected to
	 * @param cost
	 * @param latency
	 */
	public Edge(String id, Node headNode, Node tailNode, double costHT, double costTH, double latHT, double latTH)
	{
		this.id = id;
		this.headNode = headNode;
		this.tailNode = tailNode;
		this.costHT = costHT;
		this.costTH = costTH;
		this.latHT = latHT;
		this.latTH = latTH;
	}

	public Node nextNode(Node node)
	{
		if ( node == headNode )
			return tailNode;
		else if ( node == tailNode )
			return headNode;
		return null;
	}
	
	public Node getHeadNode()
	{
		return headNode;
	}
	
	public Node getTailNode()
	{
		return tailNode;
	}
	
	public void setCost(Node startNode, double cost)
	{
		if ( startNode == headNode)
			costHT = cost;
		else if ( startNode == tailNode)
			costTH = cost;
		else
			throw new RuntimeException("No such node");
	}
	
	public double getCost(Node startNode)
	{
		if ( startNode == headNode )
			return costHT;
		else if ( startNode == tailNode )
			return costTH;
		else
			throw new RuntimeException("No such node");
	}
	
	public void setLatency(Node startNode, double latency)
	{
		if ( startNode == headNode )
			latHT = latency;
		else if ( startNode == tailNode )
			latTH = latency;
		else
			throw new RuntimeException("No such node");
	}

	public double getLatency(Node startNode)
	{
		if ( startNode == headNode )
			return latHT;
		else if ( startNode == tailNode )
			return latTH;
		else
			throw new RuntimeException("No such node");
	}
	
	public boolean contains(Node node, int comparison)
	{
		if ( comparison == OBJECT )
			return ( node == headNode || node == tailNode );
		else if ( comparison == ATTRIBUTE )
			return ( headNode.compare(node) || tailNode.compare(node) );
		else
			throw new RuntimeException("No such comparison");
	}
	
	public boolean compare(Edge edge)
	{
		Node head = edge.getHeadNode();
		Node tail = edge.getTailNode();
		
		boolean isStraight = headNode.compare(head) && tailNode.compare(tail) 
			&& costHT == getCost(headNode) && costTH == getCost(tailNode) 
			&& latHT == getLatency(headNode) && latTH == getLatency(tailNode);
		
		boolean isReverse = headNode.compare(tail) && tailNode.compare(head) 
			&& costHT == getCost(tailNode) && costTH == getCost(headNode) 
			&& latHT == getLatency(tailNode) && latTH == getLatency(headNode) ;
		
		return isStraight || isReverse; 
	}
	
	public Edge clone()
	{
		return new Edge(id, headNode, tailNode, costHT, costTH, latHT, latTH);
	}
	
	public boolean swap()
	{
		return swap(tailNode);
	}
	
	public boolean swap(Node node)
	{
		if ( tailNode == node )
		{
			Node tmpNode = headNode;
			headNode = tailNode;
			tailNode = tmpNode;
			
			double tmpCostHT = costHT;
			costHT = costTH;
			costTH = tmpCostHT;
			
			double tmpLatHT = latHT;
			latHT = latTH;
			latTH = tmpLatHT;
			
			return true;
		}else if ( headNode == node )
			return true;
		return false;
	}
	
	public String toString()
	{
		return "Edge: " +
				" id: " + id + 
				" headNode: " + headNode.getId() +
				" tailNode: " + tailNode.getId() +				
				" latHT: " + getLatency(headNode)+ 
				" latTH: " + getLatency(tailNode) +
				" costHT: " + getCost(headNode) +
				" costTH: " + getCost(tailNode);
	}

	public String getId() {
		return id;
	}
	
}//end of class Edge

